package com.lisn.sgseetaface.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Environment;
import android.util.Log;

import com.lisn.sg_face.Face;
import com.lisn.sg_face.FaceTrack;
import com.lisn.sgseetaface.filiter.ScreenFiliter;
import com.lisn.sgseetaface.util.CameraHelper;
import com.lisn.sgseetaface.util.OpenGLUtils;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import static android.opengl.GLES20.GL_CLAMP_TO_EDGE;
import static android.opengl.GLES20.GL_COLOR_ATTACHMENT0;
import static android.opengl.GLES20.GL_FRAMEBUFFER;
import static android.opengl.GLES20.GL_LINEAR;
import static android.opengl.GLES20.GL_NEAREST;
import static android.opengl.GLES20.GL_RGBA;
import static android.opengl.GLES20.GL_TEXTURE_2D;
import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
import static android.opengl.GLES20.GL_TEXTURE_WRAP_S;
import static android.opengl.GLES20.GL_TEXTURE_WRAP_T;
import static android.opengl.GLES20.GL_UNSIGNED_BYTE;
import static android.opengl.GLES20.glBindFramebuffer;
import static android.opengl.GLES20.glBindTexture;
import static android.opengl.GLES20.glDeleteFramebuffers;
import static android.opengl.GLES20.glDeleteTextures;
import static android.opengl.GLES20.glFramebufferTexture2D;
import static android.opengl.GLES20.glGenFramebuffers;
import static android.opengl.GLES20.glGenTextures;
import static android.opengl.GLES20.glReadPixels;
import static android.opengl.GLES20.glTexImage2D;
import static android.opengl.GLES20.glTexParameterf;

/**
 * Author: LiShan
 * Time: 2020/8/31
 * Description: 渲染器
 */
public class SGRender implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener, Camera.PreviewCallback {

    CameraHelper mCameraHelper;

    SurfaceTexture mSurfaceTexture;

    SGView mSGView;

    int[] mTextures;

    //变换矩阵
    private float[] mtx = new float[16];

    private ScreenFiliter mScreenFiliter;

    private FaceTrack mFaceTrack;
    private int width;
    private int height;


    public SGRender(SGView douyinView) {
        this.mSGView = douyinView;

        Context context = douyinView.getContext();

        //拷贝 模型
        OpenGLUtils.copyAssets2SdCard(context, "lbpcascade_frontalface.xml",
                "/sdcard/lbpcascade_frontalface.xml");
        OpenGLUtils.copyAssets2SdCard(context, "seeta_fa_v1.1.bin",
                "/sdcard/seeta_fa_v1.1.bin");
    }

    /**
     * 创建好渲染器
     *
     * @param gl
     * @param config
     */
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //初始化操作
        mCameraHelper = new CameraHelper(Camera.CameraInfo.CAMERA_FACING_FRONT);
        mCameraHelper.setPreviewCallback(this);

        //准备好画布
        mTextures = new int[1];
        //这里创建了纹理，直接应用了，没有配置。
        GLES20.glGenTextures(mTextures.length, mTextures, 0);

        mSurfaceTexture = new SurfaceTexture(mTextures[0]);
        mSurfaceTexture.setOnFrameAvailableListener(this);

        //注意，必须在Gl线程中创建文件
        mScreenFiliter = new ScreenFiliter(mSGView.getContext());

    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        // 创建跟踪器
        mFaceTrack = new FaceTrack("/sdcard/lbpcascade_frontalface.xml",
                "/sdcard/seeta_fa_v1.1.bin", mCameraHelper.getCameraId(),
                mCameraHelper.WIDTH, mCameraHelper.HEIGHT);
        //启动跟踪器
        mFaceTrack.startTrack();

        //开启预览
        mCameraHelper.startPreview(mSurfaceTexture);
        mScreenFiliter.onReady(width, height);

        if (this.width != width || this.height != height) {
            this.width = width;
            this.height = height;
            delFrameBufferAndTexture();
            genFrameBufferAndTexture();
        }
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        //配置屏幕
        //清理屏幕, 告诉opengl需要把屏幕清理成什么颜色
        GLES20.glClearColor(0, 0, 0, 0);
        //执行上一个：glClearColor配置的屏幕颜色
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        //把摄像头的数据显示出来
        //更新纹理，然后我们才能使用opengl从surfaceTexture当中获得数据进行渲染
        mSurfaceTexture.updateTexImage();


        Face face = mFaceTrack.getFace();
        if (null != face) {
            Log.e("face", face.toString());
        }

        //SurfaceTexture比较特殊， 采用的是sampleExtension（而不是用的Sample2）
        //获得变换矩阵， 变换矩阵是一个 4 * 4 的矩阵
        mSurfaceTexture.getTransformMatrix(mtx);

        if (isTakingPhoto()) {
            ByteBuffer exportBuffer = ByteBuffer.allocate(width * height * 4);

            bindFrameBufferAndTexture();
            mScreenFiliter.onDrawFrame(mTextures[0], mtx);
            glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, exportBuffer);
            savePhoto(exportBuffer);
            unBindFrameBuffer();

            setTakingPhoto(false);
        } else {
            mScreenFiliter.onDrawFrame(mTextures[0], mtx);
        }

    }

    boolean takingPhoto;

    boolean isTakingPhoto() {
        return takingPhoto;
    }

    public void setTakingPhoto(boolean takingPhoto) {
        this.takingPhoto = takingPhoto;
    }

    int[] exportFrame = new int[1];
    int[] exportTexture = new int[1];

    public void delFrameBufferAndTexture() {
        glDeleteFramebuffers(exportFrame.length, exportFrame, 0);
        glDeleteTextures(exportTexture.length, exportTexture, 0);
    }

    public void genFrameBufferAndTexture() {
        glGenFramebuffers(exportFrame.length, exportFrame, 0);
        glGenTextures(exportTexture.length, exportTexture, 0);

        glBindTexture(GL_TEXTURE_2D, exportTexture[0]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
        setTextureParameters();
        glBindTexture(GL_TEXTURE_2D, 0);
    }

    public void setTextureParameters() {
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    }

    public void bindFrameBufferAndTexture() {
        glBindFramebuffer(GL_FRAMEBUFFER, exportFrame[0]);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, exportTexture[0], 0);
    }

    public void unBindFrameBuffer() {
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }


    public void savePhoto(final ByteBuffer buffer) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                bitmap.copyPixelsFromBuffer(buffer);
                String folderPath = Environment.getExternalStorageDirectory() + "/AAA/";
                File folder = new File(folderPath);
                if (!folder.exists() && !folder.mkdirs()) {
                    Log.e("demos", "图片目录异常");
                    return;
                }
                String filePath = folderPath + System.currentTimeMillis() + ".jpg";
                BufferedOutputStream bos = null;
                try {
                    FileOutputStream fos = new FileOutputStream(filePath);
                    bos = new BufferedOutputStream(fos);
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } finally {
                    if (bos != null) {
                        try {
                            bos.flush();
                            bos.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (bitmap != null) {
                        bitmap.recycle();
                    }
                }
            }
        }).start();
    }


    //有一个新的有效的图片的时候调用，让它调用onDrawFrame方法，通过GLSurfaceview的 requestRender()
    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
        //有数据时调用，省资源省电，然后调用 onDrawFrame，构成循环。
        mSGView.requestRender();
    }

    public void onSurfaceDestroyed() {
        mCameraHelper.stopPreview();
        //关闭跟踪器
        mFaceTrack.stopTrack();
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        //data 送去跟踪器检测人脸 与 关键点定位。 这个detector很耗时，开线程
        mFaceTrack.detector(data);
    }
}
